package com.game.graphics;

import java.awt.Image;
import java.util.ArrayList;

/**
    The Animation class manages a series of images (frames) and
    the amount of time to display each frame.
*/
public class Animation {

    private ArrayList<AnimFrame> frames;
    private int currFrameIndex;
    private long animTime;
    private long totalDuration;
    
    private long afterTime=0;
    private long count=0;//循环次数
    public Runnable runnable=null;
    public boolean stop;
    
    /**
        Creates a new, empty Animation.
    */
    public Animation() {
        this(new ArrayList<AnimFrame>(), 0);
    }


    private Animation(ArrayList<AnimFrame> frames, long totalDuration) {
        this.frames = frames;
        this.totalDuration = totalDuration;
        start();
    }


    /**
        Creates a duplicate of this animation. The list of frames
        are shared between the two Animations, but each Animation
        can be animated independently.
    */
    public Object clone() {
        return new Animation(frames, totalDuration);
    }


    /**
        Adds an image to the animation with the specified
        duration (time to display the image).
    */
    public synchronized void addFrame(Image image,
        long duration)
    {
        totalDuration += duration;
        frames.add(new AnimFrame(image, totalDuration));
    }
    
    public synchronized void addFrame(MyImage myImage,long duration)
    {
    	totalDuration += duration;
    	frames.add(new AnimFrame(myImage.images, totalDuration,myImage.width,myImage.height));
    }
    
    public synchronized void addFrame(Image image,
    		long duration,int width,int height)
    {
    	totalDuration += duration;
    	frames.add(new AnimFrame(image, totalDuration,width,height));
    }


    /**
        Starts this animation over from the beginning.
    */
    public synchronized void start() {
        animTime = 0;
        currFrameIndex = 0;
        stop=false;
        count=0l;
    }


    /**
        Updates this animation's current image (frame), if
        neccesary.
    */
    public synchronized void update(long elapsedTime) {
        if (frames.size() > 1) {
        	if(!isStop())
        		animTime += elapsedTime;
            
        	if(runnable!=null && animTime+count*totalDuration>afterTime){
        		new Thread(runnable).run();
        	}
            
            if (animTime >= totalDuration) {
                animTime = animTime % totalDuration;
                currFrameIndex = 0;
                count++;
            }

            while (animTime > getFrame(currFrameIndex).endTime) {
                currFrameIndex++;
            }
        }
    }


    /**
        Gets this Animation's current image. Returns null if this
        animation has no images.
    */
    public synchronized Image[] getImage() {
        if (frames.size() == 0) {
            return null;
        }
        else {
            return getFrame(currFrameIndex).myImage.images;
        }
    }
    public synchronized MyImage getMyImage() {
    	if (frames.size() == 0) {
    		return null;
    	}
    	else {
    		return getFrame(currFrameIndex).myImage;
    	}
    }


    private AnimFrame getFrame(int i) {
        return (AnimFrame)frames.get(i);
    }


    private class AnimFrame {
    	
    	MyImage myImage;
        long endTime;

        public AnimFrame(Image image, long endTime) {
            this(image, endTime, image.getWidth(null), image.getHeight(null));
        }
        public AnimFrame(Image image, long endTime,int width,int height){
        	this(new Image[]{image},endTime,width,height);
        }
        public AnimFrame(Image[] images, long endTime,int width,int height) {
        	myImage=new MyImage();
        	this.myImage.images=images;
        	this.endTime = endTime;
        	this.myImage.width=width;
        	this.myImage.height=height;
        }
    }
    
    public long getTotalDuration() {
		return totalDuration;
	}
    
    public void after(Runnable runnable,long afterTime){
    	this.runnable=runnable;
    	this.afterTime=afterTime;
    	count=0;
    }
    
    public void after(Runnable runnable,double rate){
    	this.runnable=runnable;
    	this.afterTime=Math.round(totalDuration*rate);
    	count=0;
    }
    
    
    
    public void setStop(boolean stop) {
		this.stop = stop;
	}
    
    public void stop(){
    	setStop(true);
    }
    
    public boolean isStop() {
		return stop;
	}
}
